#include "linux/module.h"
#include "linux/init.h"
#include "linux/fs.h"
#include "linux/cdev.h"
#include "linux/kdev_t.h"
#include "linux/uaccess.h"
#include "linux/io.h"
#include "linux/wait.h"

#include "linux/poll.h"
#include "linux/signal.h"
struct chrdev
{
    dev_t dev_num;         // 设备号
    struct cdev cdev_test; // cdev
    struct class *class;   // 设备类
    struct device *device; // 设备
    char kbuf[32];
    int flag;
    struct fasync_struct *fasync;
} dev1;

// 静态声明并初始化等待队列头
DECLARE_WAIT_QUEUE_HEAD(read_wq);

//=================================================
static int open_test(struct inode *inode, struct file *file)
{
    file->private_data = &dev1;
    printk(KERN_INFO "打开文件\n");
    return 0;
}
static int release_test(struct inode *inode, struct file *file)
{
    printk(KERN_INFO "关闭文件\n");
    return 0;
}
static ssize_t read_test(struct file *file, char __user *buff, size_t size, loff_t *off)
{
    struct chrdev *test_dev = (struct chrdev *)file->private_data;

    if (file->f_flags & O_NONBLOCK)
    {
        if (test_dev->flag != 1)
            return -EAGAIN;
    }

    wait_event_interruptible(read_wq, test_dev->flag);
    if (copy_to_user(buff, test_dev->kbuf, size) != 0)
    {
        printk(KERN_ERR "从内核复制数据失败\n");
        return -1;
    }
    return 0;
}
static ssize_t write_test(struct file *file, const char __user *buff, size_t size, loff_t *off)
{
    struct chrdev *test_dev = (struct chrdev *)file->private_data;

    if (copy_from_user(test_dev->kbuf, buff, size) != 0)
    {
        printk(KERN_ERR "从用户空间复制数据失败\n");
        return -1;
    }
    test_dev->flag = 1;              // 条件设置为1
    wake_up_interruptible(&read_wq); // 并唤醒等待队列中的休眠线程

    return 0;
}

__poll_t poll_test(struct file *file, struct poll_table_struct *p)
{
    struct chrdev *test_dev = (struct chrdev *)file->private_data;
    __poll_t mask = 0;            // 初始化返回值
    poll_wait(file, &read_wq, p); // 使进程进入阻塞，如果被唤醒则从下一句执行
    if (test_dev->flag == 1)      // 如果有数据可读 设置mask并且返回
    {
        mask |= POLL_IN;
    }
    return mask;
}

int fasync_test(int fd, struct file * file , int x)
{
    struct chrdev *test_dev = (struct chrdev *)file->private_data;
    return fasync_helper(fd,file,1,&test_dev->fasync);
}
//=================================================

struct file_operations fops_test = {
    .owner = THIS_MODULE,
    .open = open_test,
    .release = release_test,
    .read = read_test,
    .write = write_test,
    .poll = poll_test,
    .fasync = fasync_test,
};

static int __init atomic_init(void)
{
    alloc_chrdev_region(&dev1.dev_num, 0, 1, "atomic_test");
    printk(KERN_INFO "主设备号为:%d,次设备号为:%d\n", MAJOR(dev1.dev_num), MINOR(dev1.dev_num));
    cdev_init(&dev1.cdev_test, &fops_test); // 设备初始化cdev结构体和file_operations关联
    dev1.cdev_test.owner = THIS_MODULE;
    cdev_add(&dev1.cdev_test, dev1.dev_num, 1); // 添加设备
    dev1.class = class_create(THIS_MODULE, "atomic_test_class");
    dev1.device = device_create(dev1.class, NULL, dev1.dev_num, NULL, "atomic_test_drive");
    return 0;
}

static void __exit atomic_exit(void)
{
    device_destroy(dev1.class, dev1.dev_num);
    class_destroy(dev1.class);
    cdev_del(&dev1.cdev_test);
    unregister_chrdev_region(dev1.dev_num, 1);
}

module_init(atomic_init);
module_exit(atomic_exit);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("逮就捕");
